#pragma once
#include "cstTime.h"
#include <json/json.h>
#ifndef _BIDCONTROL_
#include "Utility.h"
#else
#include "..\\..\\BidServer\\Utility.h"
#endif

using namespace std;

extern LPCWSTR NOT_EXISTS_TAG;

class CINIOperater;
class IArrayCallback
{
public:
	virtual void writeElement(CINIOperater *oper, LPCWSTR section, LPCWSTR key, LPCVOID data, intptr_t idx) const = 0;
	virtual void readElement(const CINIOperater *oper, LPCWSTR section, LPCWSTR key, LPCVOID data, intptr_t idx) = 0;
	virtual LPCVOID allocElement(intptr_t num) = 0;
};

class CINIOperater: public CObject
{
	DECLARE_DYNAMIC(CINIOperater)
public:
	virtual void WriteString(LPCWSTR section, LPCWSTR key, LPCWSTR value) = 0;
	virtual void WriteInt(LPCWSTR section, LPCWSTR key, int value) = 0;
	virtual bool hasSection(LPCWSTR section) const = 0;
	virtual bool hasKey(LPCWSTR section, LPCWSTR key) const = 0;
	virtual void clearKey(LPCWSTR section, LPCWSTR key) = 0;
	virtual LPCWSTR enumKeys(LPCWSTR section) const = 0;
protected:
	virtual bool getString(CString &value, LPCWSTR section, LPCWSTR key, LPCWSTR defaultValue) const = 0;
	virtual bool getInt(int &value, LPCWSTR section, LPCWSTR key, int defaultValue) const = 0;
public:
	CString GetString(LPCWSTR section, LPCWSTR key, LPCWSTR defaultValue) const;
	virtual int GetInt(LPCWSTR section, LPCWSTR key, int defaultValue) const;
	int GetIntWithRange(LPCWSTR section, LPCWSTR key, int defaultValue, int rangeMin, int rangeMax) const;
	bool GetBoolean(LPCWSTR section, LPCWSTR key, bool defaultValue) const;
	cst_Time GetTime(LPCWSTR section, LPCWSTR key, const cst_Time &defaultValue) const;
	CPoint GetPoint(LPCWSTR section, LPCWSTR key, const CPoint &defaultValue) const;
	byte GetByte(LPCWSTR section, LPCWSTR key, byte defaultValue) const;
	char GetChar(LPCWSTR section, LPCWSTR key, char defaultValue) const;

	void WriteBoolean(LPCWSTR section, LPCWSTR key, bool value);
	void WriteTime(LPCWSTR section, LPCWSTR key, const cst_Time *pValue);
	void WritePoint(LPCWSTR section, LPCWSTR key, const CPoint *pValue);
	void WriteByte(LPCWSTR section, LPCWSTR key, byte value);
	virtual LPCVOID ReadArray(LPCWSTR section, LPCWSTR key, intptr_t &num, IArrayCallback *callback) const;
	virtual void WriteArray(LPCWSTR section, LPCWSTR key, LPCVOID data, intptr_t num, const IArrayCallback *callback);
protected:
	void FormatSection(LPCWSTR sec_in, LPCWSTR key_in, LPWSTR sec, LPWSTR key) const;
	CString FormatToString(CString value) const;
	CString StringToFormat(LPCWSTR value) const;
};

class CINIOperaterDefault : public CINIOperater
{
	DECLARE_DYNAMIC(CINIOperaterDefault)
public:
	void WriteString(LPCWSTR section, LPCWSTR key, LPCWSTR value) override;
	void WriteInt(LPCWSTR section, LPCWSTR key, int value) override;
	bool hasSection(LPCWSTR section) const override;
	bool hasKey(LPCWSTR section, LPCWSTR key) const override;
	void clearKey(LPCWSTR section, LPCWSTR key) override { WriteString(section, key, nullptr); }
	LPCWSTR enumKeys(LPCWSTR section) const override;
protected:
	bool getString(CString &value, LPCWSTR section, LPCWSTR key, LPCWSTR defaultValue) const override;
	bool getInt(int &value, LPCWSTR section, LPCWSTR key, int defaultValue) const override;
protected:
	bool RegItemExists(HKEY hKey, LPCWSTR name, bool isKey) const;
};

class CINIOperaterFile : public CINIOperater
{
	DECLARE_DYNAMIC(CINIOperaterFile)
public:
	CINIOperaterFile(LPCWSTR iniFile) :m_iniFile(iniFile) {};
	void WriteString(LPCWSTR section, LPCWSTR key, LPCWSTR value) override;
	void WriteInt(LPCWSTR section, LPCWSTR key, int value) override;
	bool hasSection(LPCWSTR section) const override;
	bool hasKey(LPCWSTR section, LPCWSTR key) const override;
	void clearKey(LPCWSTR section, LPCWSTR key) override { WriteString(section, key, nullptr); }
	LPCWSTR enumKeys(LPCWSTR section) const override;
protected:
	bool getString(CString &value, LPCWSTR section, LPCWSTR key, LPCWSTR defaultValue) const override;
	bool getInt(int &value, LPCWSTR section, LPCWSTR key, int defaultValue) const override;
protected:
	LPCWSTR m_iniFile;
};

class CINIOperaterJson : public CINIOperater
{
	DECLARE_DYNAMIC(CINIOperaterJson)
public:
	CINIOperaterJson() {}
	CINIOperaterJson(Json::Value &root) { m_root = root; }
	void WriteString(LPCWSTR section, LPCWSTR key, LPCSTR value);
	void WriteString(LPCWSTR section, LPCWSTR key, LPCWSTR value) override;
	void WriteInt(LPCWSTR section, LPCWSTR key, int value) override;
	bool hasSection(LPCWSTR section) const override;
	bool hasKey(LPCWSTR section, LPCWSTR key) const override;
	void clearKey(LPCWSTR section, LPCWSTR key) override;
	LPCWSTR enumKeys(LPCWSTR section) const override;
protected:
	bool getString(CString &value, LPCWSTR section, LPCWSTR key, LPCWSTR defaultValue) const override;
	bool getInt(int &value, LPCWSTR section, LPCWSTR key, int defaultValue) const override;
public:
	LPCSTR getJsonString();
	bool buildJson(LPCSTR orgStr);
	void WriteBool(LPCWSTR section, LPCWSTR key, bool value);
	LPCVOID ReadArray(LPCWSTR section, LPCWSTR key, intptr_t &num, IArrayCallback *callback) const override;
	void WriteArray(LPCWSTR section, LPCWSTR key, LPCVOID data, intptr_t num, const IArrayCallback *callback) override;
protected:
	LPCSTR getJsonString_real();
	bool buildJson_real(LPCSTR orgStr);
	const Json::Value* GetField(LPCWSTR section) const;
	Json::Value* GetField(LPCWSTR section, bool addWhenNotExists);
	Json::Value* GetField_real(LPCWSTR section, bool addWhenNotExists);
	bool getString_real(CString &value, LPCWSTR section, LPCWSTR key, LPCWSTR defaultValue) const;
	bool getInt_real(int &value, LPCWSTR section, LPCWSTR key, int defaultValue) const;
	LPCVOID ReadArray_real(LPCWSTR section, LPCWSTR key, intptr_t &num, IArrayCallback *callback) const;
	Json::Value m_root;
};

class CParameter
{
public:
	CParameter(LPCWSTR sec) :m_initialized(false) { wcscpy_s(section, sec); }
	virtual ~CParameter() {}
	LPCWSTR getSection() const { return section; }
	virtual void readINI(const CINIOperater *oper) = 0;
	virtual void writeINI(CINIOperater *oper) const = 0;
	virtual void buildExtra() = 0;
	virtual void clearExtra() = 0;
	void rdINI() { CINIOperaterDefault operDefault; readINI(&operDefault); }
	void wrINI() const { CINIOperaterDefault operDefault; writeINI(&operDefault); }
protected:
	bool m_initialized;
	wchar_t section[100];
};

class CWebParameter : public CParameter
{
public:
	static LPCWSTR secName(bool bSimulate)
	{
		return bSimulate ? L"Simulate" : L"Formal";
	}
	static LPCWSTR stampKey(bool isMini)
	{
		return isMini ? L"ministamp" :
#ifndef _WEBKIT_NEW
			L"timestamp";
#else
			L"h5stamp";
#endif
	}
	static LPCWSTR versionKey(bool isMini)
	{
		return isMini ? L"miniversion" : 
#ifndef _WEBKIT_NEW
			L"timeversion";
#else
			L"h5version";
#endif
	}
	CWebParameter(bool bSimulate, LPCWSTR sec, ...) :CParameter(L"")
	{
		m_bSimulate = bSimulate;
		va_list pArgList;
		va_start(pArgList, sec);
		size_t bufLength = sizeof(section) / sizeof(wchar_t);
		swprintf_s(section, L"%s\\", CWebParameter::secName(m_bSimulate));
		bufLength -= wcslen(section);
		_vsntprintf_s(section + wcslen(section), bufLength, bufLength, sec, pArgList);
		va_end(pArgList);
	}
	bool isSimulate() const { return m_bSimulate; }
	void ReadSimulate()
	{
		bool bSimulate = m_bSimulate; setSimulate(true); rdINI(); setSimulate(bSimulate);
	}
protected:
	void setSimulate(bool bSimulate)
	{
		if (m_bSimulate == bSimulate) return;
		m_bSimulate = bSimulate;
		LPCWSTR sec = copyStr(wcschr(section, '\\')); if (!sec) return;
		swprintf_s(section, L"%s%s", CWebParameter::secName(m_bSimulate), sec);
		HeapFree(GetProcessHeap(), 0, (LPVOID)sec);
	}
	bool m_bSimulate;
};

class CCommonParameter :public CParameter
{
public:
	static LPCWSTR secName()
	{
#ifndef _WEBKIT_NEW
		return L"Common";
#else
		return L"CommonNew";
#endif
	}
	CCommonParameter() :CParameter(secName()) {}
};
